#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

////////////////////////////////////////////////////////////////////////////////////////////////////
// ПРОГРАММНЫЙ ИНТЕРФЕЙС
//

// Возвращает дерево значений, заполненное данными для выбора узла обмена. В дереве 2 уровня: 
// план обмена->узлы обмена. Служебные узлы выброшены. 
//
// Параметры:
//    ОбъектДанных - Ссылка или структура со значениями измерений набор записей. Для этих данных 
//                   которых  анализируются узлы обмена. Если не указано, то для всех
//    ИмяТаблицы   - Если ОбъектДанных - структура, то имя таблицы для набора записей
//
// Колонки в результате:
//    - Наименование                  - Представление плана обмена или узла обмена
//    - ИндексКартинки                - 1=план обмена, 2=узел , 3=помеченный для удаления узел
//    - ИндексКартинкиАвторегистрация - Если не указан параметр ОбъектДанных, то Неопределено 
//                                      Иначе: 0=нет, 1=запрещена, 2=разрешена.
//                                      Неопределено для плана обмена
//    - ПланОбменаИмя                 - Имя плана обмена узла
//    - Ссылка                        - Ссылка узла, Неопределено для плана обмена
//    - Код                           - Код узла, Неопределено для плана обмена
//    - НомерОтправленного            - Данные узла
//    - НомерПринятого                - Данные узла
//    - НомерСообщения                - Если указан объект, то номер сообщения для него, иначе NULL
//    - НеВыгружалось                 - Если указан объект, то флаг выгрузки, иначе NULL
//    - Пометка                       - Если указан объект, то 0 = нет регистрации, 1 - есть, иначе всегда 0
//    - ИсходнаяПометка               - Копия "Пометка"
//    - ИдентификаторСтроки           - Индекс добавленной строки (обход дерева сверху вниз слева направо)
//
Функция СформироватьДеревоУзлов(ОбъектДанных = Неопределено, ИмяТаблицы = Неопределено) Экспорт

	Дерево = Новый ДеревоЗначений;
	Колонки = Дерево.Колонки;
	Строки  = Дерево.Строки;

	Колонки.Добавить("Наименование");
	Колонки.Добавить("ИндексКартинки");
	Колонки.Добавить("ИндексКартинкиАвторегистрация");
	Колонки.Добавить("ПланОбменаИмя");
	Колонки.Добавить("Ссылка");
	Колонки.Добавить("Код");
	Колонки.Добавить("НомерОтправленного");
	Колонки.Добавить("НомерПринятого");
	Колонки.Добавить("НомерСообщения");
	Колонки.Добавить("НеВыгружалось");
	Колонки.Добавить("Пометка");
	Колонки.Добавить("ИсходнаяПометка");
	Колонки.Добавить("ИдентификаторСтроки");

	Запрос = Новый Запрос;
	Если ОбъектДанных = Неопределено Тогда
		МетаОбъект = Неопределено;
		ТекстЗапроса = "
					   |ВЫБРАТЬ
					   |	ПРЕДСТАВЛЕНИЕССЫЛКИ(Ссылка) КАК Наименование,
					   |	ВЫБОР 
					   |		КОГДА ПометкаУдаления ТОГДА 2 ИНАЧЕ 1
					   |	КОНЕЦ КАК ИндексКартинки,
					   |
					   |	""{0}""            КАК ПланОбменаИмя,
					   |	Код                КАК Код,
					   |	Ссылка             КАК Ссылка,
					   |	НомерОтправленного КАК НомерОтправленного,
					   |	НомерПринятого     КАК НомерПринятого,
					   |	NULL               КАК НомерСообщения,
					   |	NULL               КАК НеВыгружалось,
					   |	0                  КАК Пометка,
					   |	0                  КАК ИсходнаяПометка
					   |ИЗ
					   |	ПланОбмена.{0} КАК ПланОбмена
					   |ГДЕ
					   |	ПланОбмена.Ссылка<>&ФильтрУзлов
					   |";

	Иначе
		Если ТипЗнч(ОбъектДанных) = Тип("Структура") Тогда
			ТекстЗапроса = "";
			Для Каждого КлючЗначение Из ОбъектДанных Цикл
				ТекИмя = КлючЗначение.Ключ;
				ТекстЗапроса = ТекстЗапроса + "
											  |И ТаблицаИзменений." + ТекИмя + "=&" + ТекИмя;
				Запрос.УстановитьПараметр(ТекИмя, ОбъектДанных[ТекИмя]);
			КонецЦикла;
			ТекИмяТаблицы = ИмяТаблицы;
			МетаОбъект    = МетаданныеПоПолномуИмени(ИмяТаблицы);

		ИначеЕсли ТипЗнч(ОбъектДанных) = Тип("Строка") Тогда
			ТекстЗапроса  = "";
			ТекИмяТаблицы = ОбъектДанных;
			МетаОбъект    = МетаданныеПоПолномуИмени(ОбъектДанных);

		Иначе
			ТекстЗапроса = "
						   |И ТаблицаИзменений.Ссылка=&ОбъектРегистрации";
			Запрос.УстановитьПараметр("ОбъектРегистрации", ОбъектДанных);

			МетаОбъект    = ОбъектДанных.Метаданные();
			ТекИмяТаблицы = МетаОбъект.ПолноеИмя();
		КонецЕсли;

		ТекстЗапроса = "
					   |ВЫБРАТЬ
					   |	ПРЕДСТАВЛЕНИЕССЫЛКИ(ПланОбмена.Ссылка) КАК Наименование,
					   |	ВЫБОР 
					   |		КОГДА ПланОбмена.Ссылка.ПометкаУдаления ТОГДА 2 ИНАЧЕ 1
					   |	КОНЕЦ КАК ИндексКартинки,
					   |
					   |	""{0}""                               КАК ПланОбменаИмя,
					   |	ПланОбмена.Ссылка.Код                 КАК Код,
					   |	ПланОбмена.Ссылка.Ссылка              КАК Ссылка,
					   |	ПланОбмена.Ссылка.НомерОтправленного  КАК НомерОтправленного,
					   |	ПланОбмена.Ссылка.НомерПринятого      КАК НомерПринятого,
					   |	ТаблицаИзменений.НомерСообщения       КАК НомерСообщения,
					   |	ВЫБОР 
					   |		КОГДА ТаблицаИзменений.НомерСообщения ЕСТЬ NULL
					   |		ТОГДА ИСТИНА
					   |		ИНАЧЕ ЛОЖЬ
					   |	КОНЕЦ КАК НеВыгружалось,
					   |	ВЫБОР 
					   |		КОГДА КОЛИЧЕСТВО(ТаблицаИзменений.Узел)>0 ТОГДА 1 
					   |		ИНАЧЕ 0
					   |	КОНЕЦ КАК Пометка,
					   |	ВЫБОР 
					   |		КОГДА КОЛИЧЕСТВО(ТаблицаИзменений.Узел)>0 ТОГДА 1 
					   |		ИНАЧЕ 0
					   |	КОНЕЦ КАК ИсходнаяПометка
					   |ИЗ
					   |	ПланОбмена.{0} КАК ПланОбмена
					   |ЛЕВОЕ СОЕДИНЕНИЕ
					   |	" + ТекИмяТаблицы + ".Изменения КАК ТаблицаИзменений
												|ПО
												|	ТаблицаИзменений.Узел=ПланОбмена.Ссылка
												|	" + ТекстЗапроса + "
																		|ГДЕ
																		|	ПланОбмена.Ссылка<>&ФильтрУзлов
																		|СГРУППИРОВАТЬ ПО 
																		|	ПланОбмена.Ссылка, 
																		|	ТаблицаИзменений.НомерСообщения
																		|";
	КонецЕсли;

	ТекНомерСтроки = 0;
	Для Каждого Мета Из Метаданные.ПланыОбмена Цикл

		ИмяПлана = Мета.Имя;
		Попытка
			ЭтотУзелПланаОбмена = ПланыОбмена[ИмяПлана].ЭтотУзел();
		Исключение
			// Разделенный режим, пропускаем узел
			Продолжить;
		КонецПопытки;

		Авторегистрация = Неопределено;
		Если МетаОбъект <> Неопределено Тогда
			ЭлементСостава = Мета.Состав.Найти(МетаОбъект);
			Если ЭлементСостава = Неопределено Тогда
				// Не входит в текущий план обмена
				Продолжить;
			КонецЕсли;
			Авторегистрация = ?(ЭлементСостава.Авторегистрация = АвтоРегистрацияИзменений.Запретить, 1, 2);
		КонецЕсли;

		ИмяПлана = Мета.Имя;
		Запрос.Текст = СтрЗаменить(ТекстЗапроса, "{0}", ИмяПлана);
		Запрос.УстановитьПараметр("ФильтрУзлов", ЭтотУзелПланаОбмена);
		Результат = Запрос.Выполнить();

		Если Не Результат.Пустой() Тогда
			СтрокаПлана = Строки.Добавить();
			СтрокаПлана.Наименование   = Мета.Представление();
			СтрокаПлана.ИндексКартинки = 0;
			СтрокаПлана.ПланОбменаИмя  = ИмяПлана;

			СтрокаПлана.ИдентификаторСтроки = ТекНомерСтроки;
			ТекНомерСтроки = ТекНомерСтроки + 1;
			
			// Сортировка по представлению, в запросе нельзя
			ВременнаяТаблица = Результат.Выгрузить();
			ВременнаяТаблица.Сортировать("Наименование");
			Для Каждого СтрокаУзла Из ВременнаяТаблица Цикл
				;
				НоваяСтрока = СтрокаПлана.Строки.Добавить();
				ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаУзла);

				НоваяСтрока.ИндексКартинкиАвторегистрация = Авторегистрация;

				НоваяСтрока.ИдентификаторСтроки = ТекНомерСтроки;
				ТекНомерСтроки = ТекНомерСтроки + 1;
			КонецЦикла;
		КонецЕсли;

	КонецЦикла;

	Возврат Дерево;
КонецФункции

// Возвращает структуру, описывающую метаданные для плана обмена.
//
// Параметры:
//    ИмяПланаОбмена - Если передана строка, то она интерпретируется как имя метаданных 
//                     плана обмена, для которого строится дерево конфигурации.
//                   - Если передан узел обмена, то дерево конфигурации строится для его плана обмена.
//                   - Если параметр неопределен, то строится дерево всей конфигурации.
//
//    Возвращает структуру с полями "СтруктураИмен", "СтруктураПредставлений", "Дерево",
// описывающую метаданные. Объекты, не входящие в состав плана обмена, выбрасываются.  
//
//    "СтруктураИмен" - структура, где имя - группа метаданных (константы, справочники и т.п.),
// значение - массив полных имен.
//
//    "СтруктураПредставлений" - структура, где имя - группа метаданных (константы, справочники
// и т.п.), значение - массив представлений. Порядок представлений  в массиве совпадает с массивом 
// полных имен.
//
//    "СтруктураАвторегистрации" - структура, где имя - группа метаданных (константы, справочники
// и т.п.), значение - массив флагов авторегистрации на узле. Порядок данных в массиве совпадает 
// с массивом полных имен. Входят только те группы, которые не входят в дерево. 
//
//    "Дерево" - дерево значений, 3 уровня: конфигурация->вид объекта->объект. 
// Колонки дерева:
//    - Наименование        - Представление вида объекта метаданных
//    - МетаПолноеИмя       - Полное имя объекта метаданных
//    - ИндексКартинки      - Зависит от метаданных
//    - Пометка             - Неопределено
//    - ИдентификаторСтроки - Индекс добавленной строки (обход дерева сверху вниз слева направо)
//    - Авторегистрация     - Если указан ИмяПланаОбмена, то для листьев: 1-разрешена, 2-запрещена. Иначе Неопределено
//
//    - КоличествоИзменений        - Неопределено, нужно для дальнейшего расчета
//    - КоличествоВыгруженных      - Неопределено, нужно для дальнейшего расчета
//    - КоличествоНевыгруженных    - Неопределено, нужно для дальнейшего расчета
//    - КоличествоИзмененийСтрокой - Неопределено, нужно для дальнейшего расчета
//
Функция СформироватьСтруктуруМетаданных(ИмяПланаОбмена = Неопределено) Экспорт

	Дерево = Новый ДеревоЗначений;
	Колонки = Дерево.Колонки;
	Колонки.Добавить("Наименование");
	Колонки.Добавить("МетаПолноеИмя");
	Колонки.Добавить("ИндексКартинки");
	Колонки.Добавить("Пометка");
	Колонки.Добавить("ИдентификаторСтроки");

	Колонки.Добавить("Авторегистрация");
	Колонки.Добавить("КоличествоИзменений");
	Колонки.Добавить("КоличествоВыгруженных");
	Колонки.Добавить("КоличествоНевыгруженных");
	Колонки.Добавить("КоличествоИзмененийСтрокой");
	
	// Корень
	СтрокаКорень = Дерево.Строки.Добавить();
	СтрокаКорень.Наименование = Метаданные.Синоним;
	СтрокаКорень.ИндексКартинки = 0;
	СтрокаКорень.ИдентификаторСтроки = 0;
	
	// Параметры
	ТекПараметры = Новый Структура("СтруктураИмен, СтруктураПредставлений, СтруктураАвторегистрации, Строки",
		Новый Структура, Новый Структура, Новый Структура, СтрокаКорень.Строки);

	Если ИмяПланаОбмена = Неопределено Тогда
		ПланОбмена = Неопределено;
	ИначеЕсли ТипЗнч(ИмяПланаОбмена) = Тип("Строка") Тогда
		ПланОбмена = Метаданные.ПланыОбмена[ИмяПланаОбмена];
	Иначе
		ПланОбмена = ИмяПланаОбмена.Метаданные();
	КонецЕсли;
	ТекПараметры.Вставить("ПланОбмена", ПланОбмена);

	Результат = Новый Структура("Дерево, СтруктураИмен, СтруктураПредставлений, СтруктураАвторегистрации", Дерево,
		ТекПараметры.СтруктураИмен, ТекПараметры.СтруктураПредставлений, ТекПараметры.СтруктураАвторегистрации);

	ТекНомерСтроки = 1;
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 1, 2, Ложь, "Константы", НСтр("ru='Константы'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 3, 4, Истина, "Справочники", НСтр("ru='Справочники'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 5, 6, Истина, "Последовательности", НСтр(
		"ru='Последовательности'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 7, 8, Истина, "Документы", НСтр("ru='Документы'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 9, 10, Истина, "ПланыВидовХарактеристик", НСтр(
		"ru='Планы видов характеристик'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 11, 12, Истина, "ПланыСчетов", НСтр(
		"ru='Планы счетов'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 13, 14, Истина, "ПланыВидовРасчета", НСтр(
		"ru='Планы видов расчета'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 15, 16, Истина, "РегистрыСведений", НСтр(
		"ru='Регистры сведений'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 17, 18, Истина, "РегистрыНакопления", НСтр(
		"ru='Регистры накопления'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 19, 20, Истина, "РегистрыБухгалтерии", НСтр(
		"ru='Регистры бухгалтерии'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 21, 22, Истина, "РегистрыРасчета", НСтр(
		"ru='Регистры расчета'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 23, 24, Истина, "БизнесПроцессы", НСтр(
		"ru='Бизнес-процессы'"));
	СформироватьУровеньМетаданных(ТекНомерСтроки, ТекПараметры, 25, 26, Истина, "Задачи", НСтр("ru='Задачи'"));

	Возврат Результат;
КонецФункции

//    Вычисляет количества изменений для объектов метаданных для узлов обмена.
//
// Параметры:
//    - СписокТаблиц - Или массив или коллекция "ключ/значение" где "значение" - массивы имен
//    - СписокУзлов  - Узел или массив списков узлов
//
// Возвращает таблицу значений. Колонки:
//    - МетаПолноеИмя           - Полное имя метаданных, для которых рассчитываем количество
//    - УзелОбмена              - Ссылка на узел обмена, для которого рассчитываем количество
//    - КоличествоИзменений     - Число
//    - КоличествоВыгруженных   - Число
//    - КоличествоНеВыгруженных - Число
//
Функция ПолучитьКоличествоИзменений(СписокТаблиц, СписокУзлов) Экспорт

	Результат = Новый ТаблицаЗначений;
	Колонки = Результат.Колонки;
	Колонки.Добавить("МетаПолноеИмя");
	Колонки.Добавить("УзелОбмена");
	Колонки.Добавить("КоличествоИзменений");
	Колонки.Добавить("КоличествоВыгруженных");
	Колонки.Добавить("КоличествоНеВыгруженных");

	Результат.Индексы.Добавить("МетаПолноеИмя");
	Результат.Индексы.Добавить("УзелОбмена");

	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("СписокУзлов", СписокУзлов);
	
	// На входе или массив или структура/соответствие со многими массивами
	Если СписокТаблиц = Неопределено Тогда
		Возврат Результат;
	ИначеЕсли ТипЗнч(СписокТаблиц) = Тип("Массив") Тогда
		Источник = Новый Структура("_", СписокТаблиц);
	Иначе
		Источник = СписокТаблиц;
	КонецЕсли;
	
	// Пачками по 200 таблиц в запросе
	Текст = "";
	Номер = 0;
	Для Каждого КлючЗначение Из Источник Цикл
		Если ТипЗнч(КлючЗначение.Значение) <> Тип("Массив") Тогда
			Продолжить;
		КонецЕсли;

		Для Каждого Элемент Из КлючЗначение.Значение Цикл
			Если ПустаяСтрока(Элемент) Тогда
				Продолжить;
			КонецЕсли;

			Текст = Текст + ?(Текст = "", "", "ОБЪЕДИНИТЬ ВСЕ") + " 
																  |ВЫБРАТЬ 
																  |	""" + Элемент + """ КАК МетаПолноеИмя,
																					   |	Узел                КАК УзелОбмена,
																					   |	КОЛИЧЕСТВО(*)              КАК КоличествоИзменений,
																					   |	КОЛИЧЕСТВО(НомерСообщения) КАК КоличествоВыгруженных,
																					   |	КОЛИЧЕСТВО(*) - КОЛИЧЕСТВО(НомерСообщения) КАК КоличествоНеВыгруженных
																					   |ИЗ
																					   |	" + Элемент + ".Изменения
																										  |ГДЕ
																										  |	Узел В (&СписокУзлов)
																										  |СГРУППИРОВАТЬ ПО
																										  |	Узел
																										  |";

			Номер = Номер + 1;
			Если Номер = 200 Тогда
				Запрос.Текст = Текст;
				Выборка = Запрос.Выполнить().Выбрать();
				Пока Выборка.Следующий() Цикл
					ЗаполнитьЗначенияСвойств(Результат.Добавить(), Выборка);
				КонецЦикла;
				Текст = "";
				Номер = 0;
			КонецЕсли;

		КонецЦикла;
	КонецЦикла;
	
	// Дочитываем хвосты
	Если Текст <> "" Тогда
		Запрос.Текст = Текст;
		Выборка = Запрос.Выполнить().Выбрать();
		Пока Выборка.Следующий() Цикл
			ЗаполнитьЗначенияСвойств(Результат.Добавить(), Выборка);
		КонецЦикла;
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Возвращает объект метаданных по его полному имени. Пустая строка обозначает конфигурацию.
//
// Параметры:
//    - ИмяМетаданных - Строка - Имя объекта метаданных, например "Справочник.Валюты" или "Константы"
//
Функция МетаданныеПоПолномуИмени(ИмяМетаданных) Экспорт

	Если ПустаяСтрока(ИмяМетаданных) Тогда
		// Вся конфигурация
		Возврат Метаданные;
	КонецЕсли;

	Значение = Метаданные.НайтиПоПолномуИмени(ИмяМетаданных);
	Если Значение = Неопределено Тогда
		Значение = Метаданные[ИмяМетаданных];
	КонецЕсли;

	Возврат Значение;
КонецФункции

// Возвращает флаг регистрации объекта на узле
//
// Параметры:
//    - Узел              - Узел плана обмена для которого получаем информацию, 
//    - ОбъектРегистрации - Объект, для которого получаем информацию. Может быть строкой - 
//                          обрабатываем метаданные, ссылкой или структурой со значениями
//                          изменений набора записей
//    - ИмяТаблицы        - Если ОбъектРегистрации - структура, то содержит имя таблицы для набора измерений
//
Функция ОбъектЗарегистрированНаУзле(Узел, ОбъектРегистрации, ИмяТаблицы = Неопределено) Экспорт
	ТипПараметра = ТипЗнч(ОбъектРегистрации);
	Если ТипПараметра = Тип("Строка") Тогда
		// Константа как метаданные
		Описание = ХарактеристикиПоМетаданным(ОбъектРегистрации);
		ТекущийОбъект = Описание.Менеджер.СоздатьМенеджерЗначения();

	ИначеЕсли ТипПараметра = Тип("Структура") Тогда
		// Набор измерений, ИмяТаблицы - чего
		Описание = ХарактеристикиПоМетаданным(ИмяТаблицы);
		ТекущийОбъект = Описание.Менеджер.СоздатьНаборЗаписей();
		Для Каждого КлючЗначение Из ОбъектРегистрации Цикл
			ТекущийОбъект.Отбор[КлючЗначение.Ключ].Установить(КлючЗначение.Значение);
		КонецЦикла;

	Иначе
		ТекущийОбъект = ОбъектРегистрации;
	КонецЕсли;

	Возврат ПланыОбмена.ИзменениеЗарегистрировано(Узел, ТекущийОбъект);
КонецФункции

// Изменяет регистрацию переданного.
//
// Параметры:
//    - Команда                 - Истина, если надо добавлять, Ложь, если удалять
//    - БезУчетаАвторегистрации - Истина, если не надо анализировать флаг авторегистрации
//    - Узел                    - Ссылка на узел плана обмена
//    - Данные                  - Ссылка, строка (полное имя метаданных), структура (измерения набора)
//                                или массив таких данных.
//    - ИмяТаблицы              - Если Данные является структурой, то содержит имя таблицы
//
// Возвращает структуру с общим числом объектов и числом успешно обработанных объектов
//
Функция ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел, Данные, ИмяТаблицы = Неопределено) Экспорт

	ПрочитатьНастройки();
	Результат = Новый Структура("Всего, Успешно", 0, 0);
	
	// Только при добавлении и работе в составе БСП
	НадоФильтрБСП = ТипЗнч(Команда) = Тип("Булево") И Команда И КонфигурацияПоддерживаетБСП
		И НастройкаКонтрольВыгрузкиОбъектов;

	Если ТипЗнч(Данные) = Тип("Массив") Тогда
		ДанныеРегистрации = Данные;
	Иначе
		ДанныеРегистрации = Новый Массив;
		ДанныеРегистрации.Добавить(Данные);
	КонецЕсли;

	Для Каждого Элемент Из ДанныеРегистрации Цикл

		Тип = ТипЗнч(Элемент);
		Значения = Новый Массив;

		Если Элемент = Неопределено Тогда
			// Вся конфигурация

			Если ТипЗнч(Команда) = Тип("Булево") И Команда Тогда
				// Добавляем регистрацию по частям
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"Константы", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"Справочники", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"Документы", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"Последовательности", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"ПланыВидовХарактеристик", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"ПланыСчетов", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"ПланыВидовРасчета", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"РегистрыСведений", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"РегистрыНакопления", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"РегистрыБухгалтерии", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"РегистрыРасчета", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"БизнесПроцессы", ИмяТаблицы));
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					"Задачи", ИмяТаблицы));
				Продолжить;
			КонецЕсли;
			
			// Удаление регистрации - платформенным методом
			Значения.Добавить(Неопределено);

		ИначеЕсли Тип = Тип("Строка") Тогда
			// Метаданные, возможно как коллекция, так и конкретный вид, на авторегистрацию смотрим
			Описание = ХарактеристикиПоМетаданным(Элемент);
			Если НадоФильтрБСП Тогда
				ДобавитьРезультаты(Результат, БСП_РегистрацияИзмененийМетаданных(Узел, Описание,
					БезУчетаАвторегистрации));
				Продолжить;

			ИначеЕсли БезУчетаАвторегистрации Тогда
				Если Описание.ЭтоКоллекция Тогда
					Для Каждого Мета Из Описание.Метаданные Цикл
						ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации,
							Узел, Мета.ПолноеИмя(), ИмяТаблицы));
					КонецЦикла;
					Продолжить;
				Иначе
					Мета = Описание.Метаданные;
					ЭлементСостава = Узел.Метаданные().Состав.Найти(Мета);
					Если ЭлементСостава = Неопределено Тогда
						Продолжить;
					КонецЕсли;
					// Константа?
					Значения.Добавить(Описание.Метаданные);
				КонецЕсли;

			Иначе
				// Отсеиваем неподходящие по авторегистрации
				Если Описание.ЭтоКоллекция Тогда
					// Регистрируем поодиночке
					Для Каждого Мета Из Описание.Метаданные Цикл
						ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации,
							Узел, Мета.ПолноеИмя(), ИмяТаблицы));
					КонецЦикла;
					Продолжить;
				Иначе
					Мета = Описание.Метаданные;
					ЭлементСостава = Узел.Метаданные().Состав.Найти(Мета);
					Если ЭлементСостава = Неопределено Или ЭлементСостава.Авторегистрация
						<> АвтоРегистрацияИзменений.Разрешить Тогда
						Продолжить;
					КонецЕсли;
					// Константа?
					Значения.Добавить(Описание.Метаданные);
				КонецЕсли;
			КонецЕсли;
			
			// Смотрим опциональные варианты, Значения[0] - метаданные конкретного вида с именем "Элемент"
			Для Каждого ТекЭлемент Из ПолучитьДополнительныеОбъектыРегистрации(Элемент, Узел, БезУчетаАвторегистрации) Цикл
				Значения.Добавить(ТекЭлемент);
			КонецЦикла;

		ИначеЕсли Тип = Тип("Структура") Тогда
			// Это или конкретный набор записей, или результат выбора ссылочного типа отбором
			Описание = ХарактеристикиПоМетаданным(ИмяТаблицы);
			Если Описание.ЭтоСсылка Тогда
				ДобавитьРезультаты(Результат, ИзменитьРегистрациюНаСервере(Команда, БезУчетаАвторегистрации, Узел,
					Элемент.Ссылка));
				Продолжить;
			КонецЕсли;
			// Конкретный набор записей, на авторегистрацию уже не смотрим
			Если НадоФильтрБСП Тогда
				ДобавитьРезультаты(Результат, БСП_РегистрацияИзмененийНабора(Узел, Элемент, Описание));
				Продолжить;
			КонецЕсли;

			Набор = Описание.Менеджер.СоздатьНаборЗаписей();
			Для Каждого КлючЗначение Из Элемент Цикл
				Набор.Отбор[КлючЗначение.Ключ].Установить(КлючЗначение.Значение);
			КонецЦикла;
			Значения.Добавить(Набор);
			// Смотрим опциональные варианты
			Для Каждого ТекЭлемент Из ПолучитьДополнительныеОбъектыРегистрации(Элемент, Узел, БезУчетаАвторегистрации,
				ИмяТаблицы) Цикл
				Значения.Добавить(ТекЭлемент);
			КонецЦикла;

		Иначе
			// Конкретная ссылка, на авторегистрацию уже не смотрим
			Если НадоФильтрБСП Тогда
				ДобавитьРезультаты(Результат, БСП_РегистрацияИзмененийСсылки(Узел, Элемент));
				Продолжить;

			КонецЕсли;
			Значения.Добавить(Элемент);
			// Смотрим опциональные варианты
			Для Каждого ТекЭлемент Из ПолучитьДополнительныеОбъектыРегистрации(Элемент, Узел, БезУчетаАвторегистрации) Цикл
				Значения.Добавить(ТекЭлемент);
			КонецЦикла;

		КонецЕсли;
		
		// Собственно регистрация, уже без фильтра
		Для Каждого ТекЗначение Из Значения Цикл
			ВыполнитьКомандуРегистрацииОбъекта(Команда, Узел, ТекЗначение);
			Результат.Успешно = Результат.Успешно + 1;
			Результат.Всего   = Результат.Всего + 1;
		КонецЦикла;

	КонецЦикла; // Перебор объектов в массиве данных для регистрации

	Возврат Результат;
КонецФункции

// Возвращает начало полного имени формы для открытия по переданному объекту
//
Функция ПолучитьИмяФормы(ТекущийОбъект = Неопределено) Экспорт

	Тип = ТипЗнч(ТекущийОбъект);
	Если Тип = Тип("ДинамическийСписок") Тогда
		Возврат ТекущийОбъект.ОсновнаяТаблица + ".";
	ИначеЕсли Тип = Тип("Строка") Тогда
		Возврат ТекущийОбъект + ".";
	КонецЕсли;

	Мета = ?(ТекущийОбъект = Неопределено, Метаданные(), ТекущийОбъект.Метаданные());
	Возврат Мета.ПолноеИмя() + ".";
КонецФункции	

// Рекурсивное обслуживание иерархических пометок с тремя состояниями в дереве. 
//
// Параметры:
//    - ДанныеСтроки - ДанныеФормыЭлементДерева. Пометка хранится в числовой колонке "Пометка"  
//
Процедура ИзменениеПометки(ДанныеСтроки) Экспорт
	ДанныеСтроки.Пометка = ДанныеСтроки.Пометка % 2;
	ПроставитьПометкиВниз(ДанныеСтроки);
	ПроставитьПометкиВверх(ДанныеСтроки);
КонецПроцедуры

// Рекурсивное обслуживание иерархических пометок с тремя состояниями в дереве. 
//
// Параметры:
//    - ДанныеСтроки - ДанныеФормыЭлементДерева. Пометка хранится в числовой колонке "Пометка"  
//
Процедура ПроставитьПометкиВниз(ДанныеСтроки) Экспорт
	Значение = ДанныеСтроки.Пометка;
	Для Каждого Потомок Из ДанныеСтроки.ПолучитьЭлементы() Цикл
		Потомок.Пометка = Значение;
		ПроставитьПометкиВниз(Потомок);
	КонецЦикла;
КонецПроцедуры

// Рекурсивное обслуживание иерархических пометок с тремя состояниями в дереве. 
//
// Параметры:
//    - ДанныеСтроки - ДанныеФормыЭлементДерева. Пометка хранится в числовой колонке "Пометка"  
//
Процедура ПроставитьПометкиВверх(ДанныеСтроки) Экспорт
	РодительСтроки = ДанныеСтроки.ПолучитьРодителя();
	Если РодительСтроки <> Неопределено Тогда
		ВсеИстина = Истина;
		НеВсеЛожь = Ложь;
		Для Каждого Потомок Из РодительСтроки.ПолучитьЭлементы() Цикл
			ВсеИстина = ВсеИстина И (Потомок.Пометка = 1);
			НеВсеЛожь = НеВсеЛожь Или Булево(Потомок.Пометка);
		КонецЦикла;
		Если ВсеИстина Тогда
			РодительСтроки.Пометка = 1;
		ИначеЕсли НеВсеЛожь Тогда
			РодительСтроки.Пометка = 2;
		Иначе
			РодительСтроки.Пометка = 0;
		КонецЕсли;
		ПроставитьПометкиВверх(РодительСтроки);
	КонецЕсли;
КонецПроцедуры

// Чтение реквизитов узла обмена.
//
// Параметры:
//    - Ссылка - Ссылка на узел обмена
//    - Данные - Список имен реквизитов для чтения через запятую
//
// Возвращает структуру с данными или Неопределено, если нет данных по переданной ссылке
//
Функция ПолучитьПараметрыУзлаОбмена(Ссылка, Данные) Экспорт
	Запрос = Новый Запрос("
						  |ВЫБРАТЬ " + Данные + " ИЗ " + Ссылка.Метаданные().ПолноеИмя() + "
																						   |ГДЕ Ссылка=&Ссылка
																						   |");
	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	Времянка = Запрос.Выполнить().Выгрузить();
	Если Времянка.Количество() = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;

	Результат = Новый Структура(Данные);
	ЗаполнитьЗначенияСвойств(Результат, Времянка[0]);
	Возврат Результат;
КонецФункции	

// Запись реквизитов узла обмена.
//
// Параметры:
//    - Ссылка - Ссылка на узел обмена
//    - Данные - Список имен реквизитов для чтения через запятую
//
Процедура УстановитьПараметрыУзлаОбмена(Ссылка, Данные) Экспорт

	ОбъектУзла = Ссылка.ПолучитьОбъект();
	Если ОбъектУзла = Неопределено Тогда
		// Ссылка на удаленный объект
		Возврат;
	КонецЕсли;

	Изменен = Ложь;
	Для Каждого Элемент Из Данные Цикл
		Если ОбъектУзла[Элемент.Ключ] <> Элемент.Значение Тогда
			Изменен = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;

	Если Изменен Тогда
		ЗаполнитьЗначенияСвойств(ОбъектУзла, Данные);
		ОбъектУзла.Записать();
	КонецЕсли;
КонецПроцедуры

// Возвращает описание данных по имени таблицы/полному имени метаданных или метаданным
//
// Параметры:
//    - ИмяТаблицы - Имя таблицы, например "Справочник.Валюты"
//
Функция ХарактеристикиПоМетаданным(ИмяТаблицыМетаданных) Экспорт

	ЭтоПоследовательность = Ложь;
	ЭтоКоллекция          = Ложь;
	ЭтоКонстанта          = Ложь;
	ЭтоСсылка             = Ложь;
	ЭтоНабор              = Ложь;
	Менеджер              = Неопределено;
	ИмяТаблицы            = "";

	Если ТипЗнч(ИмяТаблицыМетаданных) = Тип("Строка") Тогда
		Мета = МетаданныеПоПолномуИмени(ИмяТаблицыМетаданных);
		ИмяТаблицы = ИмяТаблицыМетаданных;
	ИначеЕсли ТипЗнч(ИмяТаблицыМетаданных) = Тип("Тип") Тогда
		Мета = Метаданные.НайтиПоТипу(ИмяТаблицыМетаданных);
		ИмяТаблицы = Мета.ПолноеИмя();
	Иначе
		Мета = ИмяТаблицыМетаданных;
		ИмяТаблицы = Мета.ПолноеИмя();
	КонецЕсли;

	Если Мета = Метаданные.Константы Тогда
		ЭтоКоллекция = Истина;
		ЭтоКонстанта = Истина;
		Менеджер     = Константы;

	ИначеЕсли Мета = Метаданные.Справочники Тогда
		ЭтоКоллекция = Истина;
		ЭтоСсылка    = Истина;
		Менеджер      = Справочники;

	ИначеЕсли Мета = Метаданные.Документы Тогда
		ЭтоКоллекция = Истина;
		ЭтоСсылка    = Истина;
		Менеджер     = Документы;

	ИначеЕсли Мета = Метаданные.Перечисления Тогда
		ЭтоКоллекция = Истина;
		ЭтоСсылка    = Истина;
		Менеджер     = Перечисления;

	ИначеЕсли Мета = Метаданные.ПланыВидовХарактеристик Тогда
		ЭтоКоллекция = Истина;
		ЭтоСсылка    = Истина;
		Менеджер     = ПланыВидовХарактеристик;

	ИначеЕсли Мета = Метаданные.ПланыСчетов Тогда
		ЭтоКоллекция = Истина;
		ЭтоСсылка    = Истина;
		Менеджер     = ПланыСчетов;

	ИначеЕсли Мета = Метаданные.ПланыВидовРасчета Тогда
		ЭтоКоллекция = Истина;
		ЭтоСсылка    = Истина;
		Менеджер     = ПланыВидовРасчета;

	ИначеЕсли Мета = Метаданные.БизнесПроцессы Тогда
		ЭтоКоллекция = Истина;
		ЭтоСсылка    = Истина;
		Менеджер     = БизнесПроцессы;

	ИначеЕсли Мета = Метаданные.Задачи Тогда
		ЭтоКоллекция = Истина;
		ЭтоСсылка    = Истина;
		Менеджер     = Задачи;

	ИначеЕсли Мета = Метаданные.Последовательности Тогда
		ЭтоНабор              = Истина;
		ЭтоПоследовательность = Истина;
		ЭтоКоллекция          = Истина;
		Менеджер              = Последовательности;

	ИначеЕсли Мета = Метаданные.РегистрыСведений Тогда
		ЭтоКоллекция = Истина;
		ЭтоНабор     = Истина;
		Менеджер 	 = РегистрыСведений;

	ИначеЕсли Мета = Метаданные.РегистрыНакопления Тогда
		ЭтоКоллекция = Истина;
		ЭтоНабор     = Истина;
		Менеджер     = РегистрыНакопления;

	ИначеЕсли Мета = Метаданные.РегистрыБухгалтерии Тогда
		ЭтоКоллекция = Истина;
		ЭтоНабор     = Истина;
		Менеджер     = РегистрыБухгалтерии;

	ИначеЕсли Мета = Метаданные.РегистрыРасчета Тогда
		ЭтоКоллекция = Истина;
		ЭтоНабор     = Истина;
		Менеджер     = РегистрыРасчета;

	ИначеЕсли Метаданные.Константы.Содержит(Мета) Тогда
		ЭтоКонстанта = Истина;
		Менеджер     = Константы[Мета.Имя];

	ИначеЕсли Метаданные.Справочники.Содержит(Мета) Тогда
		ЭтоСсылка = Истина;
		Менеджер  = Справочники[Мета.Имя];

	ИначеЕсли Метаданные.Документы.Содержит(Мета) Тогда
		ЭтоСсылка = Истина;
		Менеджер  = Документы[Мета.Имя];

	ИначеЕсли Метаданные.Последовательности.Содержит(Мета) Тогда
		ЭтоНабор              = Истина;
		ЭтоПоследовательность = Истина;
		Менеджер              = Последовательности[Мета.Имя];

	ИначеЕсли Метаданные.Перечисления.Содержит(Мета) Тогда
		ЭтоСсылка = Истина;
		Менеджер  = Перечисления[Мета.Имя];

	ИначеЕсли Метаданные.ПланыВидовХарактеристик.Содержит(Мета) Тогда
		ЭтоСсылка = Истина;
		Менеджер  = ПланыВидовХарактеристик[Мета.Имя];

	ИначеЕсли Метаданные.ПланыСчетов.Содержит(Мета) Тогда
		ЭтоСсылка = Истина;
		Менеджер = ПланыСчетов[Мета.Имя];

	ИначеЕсли Метаданные.ПланыВидовРасчета.Содержит(Мета) Тогда
		ЭтоСсылка = Истина;
		Менеджер  = ПланыВидовРасчета[Мета.Имя];

	ИначеЕсли Метаданные.РегистрыСведений.Содержит(Мета) Тогда
		ЭтоНабор = Истина;
		Менеджер = РегистрыСведений[Мета.Имя];

	ИначеЕсли Метаданные.РегистрыНакопления.Содержит(Мета) Тогда
		ЭтоНабор = Истина;
		Менеджер = РегистрыНакопления[Мета.Имя];

	ИначеЕсли Метаданные.РегистрыБухгалтерии.Содержит(Мета) Тогда
		ЭтоНабор = Истина;
		Менеджер = РегистрыБухгалтерии[Мета.Имя];

	ИначеЕсли Метаданные.РегистрыРасчета.Содержит(Мета) Тогда
		ЭтоНабор = Истина;
		Менеджер = РегистрыРасчета[Мета.Имя];

	ИначеЕсли Метаданные.БизнесПроцессы.Содержит(Мета) Тогда
		ЭтоСсылка = Истина;
		Менеджер = БизнесПроцессы[Мета.Имя];

	ИначеЕсли Метаданные.Задачи.Содержит(Мета) Тогда
		ЭтоСсылка = Истина;
		Менеджер = Задачи[Мета.Имя];

	Иначе
		МетаРодитель = Мета.Родитель();
		Если МетаРодитель <> Неопределено И Метаданные.РегистрыРасчета.Содержит(МетаРодитель) Тогда
			// Перерасчет
			ЭтоНабор = Истина;
			Менеджер = РегистрыРасчета[МетаРодитель.Имя].Перерасчеты[Мета.Имя];
		КонецЕсли;

	КонецЕсли;

	Возврат Новый Структура("ИмяТаблицы, Метаданные, Менеджер, ЭтоНабор, ЭтоСсылка, ЭтоКонстанта, ЭтоПоследовательность, ЭтоКоллекция",
		ИмяТаблицы, Мета, Менеджер, ЭтоНабор, ЭтоСсылка, ЭтоКонстанта, ЭтоПоследовательность, ЭтоКоллекция);

КонецФункции

// Возвращает таблицу, описывающую измерения для регистрации изменений набора данных
//
// Параметры:
//    - ИмяТаблицы   - Имя таблицы, например "РегистрСведений.КурсыВалют"
//    - ВсеИзмерения - Флаг того, что для регистра сведений получаем все измерения, а не 
//                     только основные и ведущие
//
// Возвращает таблицу с колонками:
//    - Имя         - Строка имени измерения
//    - ТипЗначения - ОписаниеТипов
//    - Заголовок   - Представление для измерения
//
Функция ИзмеренияНабораЗаписей(ИмяТаблицы, ВсеИзмерения = Ложь) Экспорт

	Если ТипЗнч(ИмяТаблицы) = Тип("Строка") Тогда
		Мета = МетаданныеПоПолномуИмени(ИмяТаблицы);
	Иначе
		Мета = ИмяТаблицы;
	КонецЕсли;
	
	// Определяем ключевые поля
	Измерения = Новый ТаблицаЗначений;
	Колонки = Измерения.Колонки;
	Колонки.Добавить("Имя");
	Колонки.Добавить("ТипЗначения");
	Колонки.Добавить("Заголовок");

	Если Не ВсеИзмерения Тогда
		// Что-то регистрируемое
		НеУчитывать = "НомерСообщения, Узел,";

		Запрос = Новый Запрос("ВЫБРАТЬ * ИЗ " + Мета.ПолноеИмя() + ".Изменения ГДЕ ЛОЖЬ");
		ПустойРезультат = Запрос.Выполнить();
		Для Каждого КолонкаРезультата Из ПустойРезультат.Колонки Цикл
			ИмяКолонки = КолонкаРезультата.Имя;
			Если Найти(НеУчитывать, ИмяКолонки + ",") = 0 Тогда
				Строка = Измерения.Добавить();
				Строка.Имя         = ИмяКолонки;
				Строка.ТипЗначения = КолонкаРезультата.ТипЗначения;

				МетаИзм = Мета.Измерения.Найти(ИмяКолонки);
				Строка.Заголовок = ?(МетаИзм = Неопределено, ИмяКолонки, МетаИзм.Представление());
			КонецЕсли;
		КонецЦикла;

		Возврат Измерения;
	КонецЕсли;
	
	// Все измерения

	ЭтоРегистрСведений = Метаданные.РегистрыСведений.Содержит(Мета);
	
	// Регистратор
	Если Метаданные.РегистрыНакопления.Содержит(Мета) Или Метаданные.РегистрыБухгалтерии.Содержит(Мета)
		Или Метаданные.РегистрыРасчета.Содержит(Мета) Или (ЭтоРегистрСведений И Мета.РежимЗаписи
		= Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.ПодчинениеРегистратору)
		Или Метаданные.Последовательности.Содержит(Мета) Тогда
		Строка = Измерения.Добавить();
		Строка.Имя         = "Регистратор";
		Строка.ТипЗначения = Документы.ТипВсеСсылки();
		Строка.Заголовок   = "Регистратор";
	КонецЕсли;
	
	// Период
	Если ЭтоРегистрСведений И Мета.ОсновнойОтборПоПериоду Тогда
		Строка = Измерения.Добавить();
		Строка.Имя         = "Период";
		Строка.ТипЗначения = Новый ОписаниеТипов("Дата");
		Строка.Заголовок   = "Период";
	КонецЕсли;
	
	// Измерения
	Если ЭтоРегистрСведений Тогда
		Для Каждого МетаИзм Из Мета.Измерения Цикл
			Строка = Измерения.Добавить();
			Строка.Имя         = МетаИзм.Имя;
			Строка.ТипЗначения = МетаИзм.Тип;
			Строка.Заголовок   = МетаИзм.Представление();
		КонецЦикла;
	КонецЕсли;
	
	// Перерасчет
	Если Метаданные.РегистрыРасчета.Содержит(Мета.Родитель()) Тогда
		Строка = Измерения.Добавить();
		Строка.Имя         = "ОбъектПерерасчета";
		Строка.ТипЗначения = Документы.ТипВсеСсылки();
		Строка.Заголовок   = "Объект перерасчета";
	КонецЕсли;

	Возврат Измерения;
КонецФункции

// Модифицирует таблицу формы, добавляя туда колонки
//
// Параметры:
//    - ТаблицаФормы   - Элемент, связанный с данными, в который будут добавлены колонки данных
//    - СохранятьИмена - Список имен колонок, которые будут сохранены, через запятую.
//    - Добавлять      - Коллекция добавляемых колонок  или перечислимое с атрибутами Имя, ТипЗначения, Заголовок
//    - ГруппаКолонок  - Группа колонок, в которую происходит добавление
//
Процедура ДобавитьКолонкиВТаблицуФормы(ТаблицаФормы, СохранятьИмена, Добавлять, ГруппаКолонок = Неопределено) Экспорт

	Форма = ФормаЭлементаФормы(ТаблицаФормы);
	ЭлементыФормы = Форма.Элементы;
	ИмяРеквизитаТаблицы = ТаблицаФормы.ПутьКДанным;

	Сохраняемые = Новый Структура(СохранятьИмена);
	СохраняемыеПутиДанных = Новый Соответствие;
	Для Каждого Элемент Из Сохраняемые Цикл
		СохраняемыеПутиДанных.Вставить(ИмяРеквизитаТаблицы + "." + Элемент.Ключ, Истина);
	КонецЦикла;

	ЭтоДинамическийСписок = Ложь;
	Для Каждого Реквизит Из Форма.ПолучитьРеквизиты() Цикл
		Если Реквизит.Имя = ИмяРеквизитаТаблицы И Реквизит.ТипЗначения.СодержитТип(Тип("ДинамическийСписок")) Тогда
			ЭтоДинамическийСписок = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;

	// Динамический пересоздает реквизиты сам
	Если Не ЭтоДинамическийСписок Тогда
		УдаляемыеИмена = Новый Массив;
		
		// Удаляем все реквизиты, которые не перечислены в СохранятьИмена
		Для Каждого Реквизит Из Форма.ПолучитьРеквизиты(ИмяРеквизитаТаблицы) Цикл
			ТекИмя = Реквизит.Имя;
			Если Не Сохраняемые.Свойство(ТекИмя) Тогда
				УдаляемыеИмена.Добавить(Реквизит.Путь + "." + ТекИмя);
			КонецЕсли;
		КонецЦикла;

		Добавляемые = Новый Массив;
		Для Каждого Колонка Из Добавлять Цикл
			ТекИмя = Колонка.Имя;
			Если Не Сохраняемые.Свойство(ТекИмя) Тогда
				Добавляемые.Добавить( Новый РеквизитФормы(ТекИмя, Колонка.ТипЗначения, ИмяРеквизитаТаблицы,
					Колонка.Заголовок));
			КонецЕсли;
		КонецЦикла;

		Форма.ИзменитьРеквизиты(Добавляемые, УдаляемыеИмена);
	КонецЕсли;
	
	// Удаляем элементы
	Родитель = ?(ГруппаКолонок = Неопределено, ТаблицаФормы, ГруппаКолонок);

	Удалять = Новый Массив;
	Для Каждого Элемент Из Родитель.ПодчиненныеЭлементы Цикл
		Удалять.Добавить(Элемент);
	КонецЦикла;
	Для Каждого Элемент Из Удалять Цикл
		Если ТипЗнч(Элемент) <> Тип("ГруппаФормы") И СохраняемыеПутиДанных[Элемент.ПутьКДанным] = Неопределено Тогда
			ЭлементыФормы.Удалить(Элемент);
		КонецЕсли;
	КонецЦикла;
	
	// Создаем элементы
	Префикс = ТаблицаФормы.Имя;
	Для Каждого Колонка Из Добавлять Цикл
		ТекИмя = Колонка.Имя;
		ЭлФормы = ЭлементыФормы.Вставить(Префикс + ТекИмя, Тип("ПолеФормы"), Родитель);
		ЭлФормы.Вид = ВидПоляФормы.ПолеВвода;
		ЭлФормы.ПутьКДанным = ИмяРеквизитаТаблицы + "." + ТекИмя;
		ЭлФормы.Заголовок = Колонка.Заголовок;
	КонецЦикла;

КонецПроцедуры	

// Возвращает подробное представление объекта.
//
// Параметры:
//    - ОбъектПредставления - Объект, представление которого получаем
//
Функция ПредставлениеСсылки(ОбъектПредставления) Экспорт

	Если ТипЗнч(ОбъектПредставления) = Тип("Строка") Тогда
		// Метаданные 
		Мета = Метаданные.НайтиПоПолномуИмени(ОбъектПредставления);
		Результат = Мета.Представление();
		Если Метаданные.Константы.Содержит(Мета) Тогда
			Результат = Результат + " (константа)";
		КонецЕсли;
		Возврат Результат;
	КонецЕсли;
	
	// Ссылка
	Результат = "";
	Если Метаданные.ОбщиеМодули.Найти("ОбщегоНазначения") <> Неопределено Тогда
		Попытка
			Результат = Вычислить("ОбщегоНазначения.ПредметСтрокой(ОбъектПредставления)");
		Исключение
		КонецПопытки;
	КонецЕсли;

	Если ПустаяСтрока(Результат) И ОбъектПредставления <> Неопределено И Не ОбъектПредставления.Пустая() Тогда
		Мета = ОбъектПредставления.Метаданные();
		Если Метаданные.Документы.Содержит(Мета) Тогда
			Результат = Строка(ОбъектПредставления);
		Иначе
			Представление = Мета.ПредставлениеОбъекта;
			Если ПустаяСтрока(Представление) Тогда
				Представление = Мета.Представление();
			КонецЕсли;
			Результат = Строка(ОбъектПредставления);
			Если Не ПустаяСтрока(Представление) Тогда
				Результат = Результат + " (" + Представление + ")";
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;

	Если ПустаяСтрока(Результат) Тогда
		Результат = НСтр("ru = 'не задано'");
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Возвращает флаг того, что работа происходит в файловой базе
//
Функция ЭтоФайловаяБаза() Экспорт
	Возврат Найти(СтрокаСоединенияИнформационнойБазы(), "File=") > 0;
КонецФункции

//  Читает текущие данные из динамического списка по его настройкам и возвращает в виде таблицы значений
//
// Параметры:
//    - ИсточникДанных - ДинамическийСписок, реквизит формы
//
Функция ТекущиеДанныеДинамическогоСписка(ИсточникДанных) Экспорт

	СхемаКомпоновки = Новый СхемаКомпоновкиДанных;

	Источник = СхемаКомпоновки.ИсточникиДанных.Добавить();
	Источник.Имя = "Источник";
	Источник.ТипИсточникаДанных = "local";

	Набор = СхемаКомпоновки.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
	Набор.Запрос = ИсточникДанных.ТекстЗапроса;
	Набор.АвтоЗаполнениеДоступныхПолей = Истина;
	Набор.ИсточникДанных = Источник.Имя;
	Набор.Имя = Источник.Имя;

	ИсточникНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновки);
	Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
	Компоновщик.Инициализировать(ИсточникНастроек);

	ТекНастройки = Компоновщик.Настройки;
	
	// Выбранные поля
	Для Каждого Элемент Из ТекНастройки.Выбор.ДоступныеПоляВыбора.Элементы Цикл
		Если Не Элемент.Папка Тогда
			Поле = ТекНастройки.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
			Поле.Использование = Истина;
			Поле.Поле = Элемент.Поле;
		КонецЕсли;
	КонецЦикла;
	Группа = ТекНастройки.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
	Группа.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));

	// Отбор
	СкопироватьОтборКомпоновкиДанных(ТекНастройки.Отбор, ИсточникДанных.Отбор);

	// Выводим
	КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
	Макет = КомпоновщикМакета.Выполнить(СхемаКомпоновки, ТекНастройки, , , Тип(
		"ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
	Процессор = Новый ПроцессорКомпоновкиДанных;
	Процессор.Инициализировать(Макет);
	Вывод  = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;

	Результат = Новый ТаблицаЗначений;
	Вывод.УстановитьОбъект(Результат);
	Вывод.Вывести(Процессор);

	Возврат Результат;
КонецФункции

// Читаем настройки из общего хранилища
//
Процедура ПрочитатьНастройки(КлючНастройки = "") Экспорт

	КлючОбъекта = Метаданные().ПолноеИмя() + ".Форма.Форма";

	ТекущиеНастройки = ХранилищеОбщихНастроек.Загрузить(КлючОбъекта);
	Если ТипЗнч(ТекущиеНастройки) <> Тип("Соответствие") Тогда
		// Умолчания
		ТекущиеНастройки = Новый Соответствие;
		ТекущиеНастройки.Вставить("НастройкаАвторегистрацияДвижений", Ложь);
		ТекущиеНастройки.Вставить("НастройкаАвторегистрацияПоследовательностей", Ложь);
		ТекущиеНастройки.Вставить("НастройкаАдресВнешнейОбработкиЗапросов", "");
		ТекущиеНастройки.Вставить("НастройкаКонтрольВыгрузкиОбъектов", Истина); // Проверять через БСП
		ТекущиеНастройки.Вставить("НастройкаВариантНомераСообщения", 0);     // Регистрировать как новое
	КонецЕсли;

	НастройкаАвторегистрацияДвижений            = ТекущиеНастройки["НастройкаАвторегистрацияДвижений"];
	НастройкаАвторегистрацияПоследовательностей = ТекущиеНастройки["НастройкаАвторегистрацияПоследовательностей"];
	НастройкаАдресВнешнейОбработкиЗапросов      = ТекущиеНастройки["НастройкаАдресВнешнейОбработкиЗапросов"];
	НастройкаКонтрольВыгрузкиОбъектов           = ТекущиеНастройки["НастройкаКонтрольВыгрузкиОбъектов"];
	НастройкаВариантНомераСообщения             = ТекущиеНастройки["НастройкаВариантНомераСообщения"];

	ПроверитьКорректностьНастроек(КлючНастройки);
КонецПроцедуры

// Устанавливаем флаги поддержки БСП
//
Процедура ПрочитатьПризнакПоддержкиБСП() Экспорт
	КонфигурацияПоддерживаетБСП = БСП_ДоступнаТребуемаяВерсия();

	Если КонфигурацияПоддерживаетБСП Тогда
		// Используем внешний интерфейс регистрации
		ДоступнаРегистрацияСредствамиБСП  = БСП_ДоступнаТребуемаяВерсия("2.1.5.11");
	Иначе
		ДоступнаРегистрацияСредствамиБСП = Ложь;
	КонецЕсли;
КонецПроцедуры

// Пишем настройки в общее хранилище
//
Процедура СохранитьНастройки(КлючНастройки = "") Экспорт

	КлючОбъекта = Метаданные().ПолноеИмя() + ".Форма.Форма";

	ТекущиеНастройки = Новый Соответствие;
	ТекущиеНастройки.Вставить("НастройкаАвторегистрацияДвижений", НастройкаАвторегистрацияДвижений);
	ТекущиеНастройки.Вставить("НастройкаАвторегистрацияПоследовательностей",
		НастройкаАвторегистрацияПоследовательностей);
	ТекущиеНастройки.Вставить("НастройкаАдресВнешнейОбработкиЗапросов", НастройкаАдресВнешнейОбработкиЗапросов);
	ТекущиеНастройки.Вставить("НастройкаКонтрольВыгрузкиОбъектов", НастройкаКонтрольВыгрузкиОбъектов);
	ТекущиеНастройки.Вставить("НастройкаВариантНомераСообщения", НастройкаВариантНомераСообщения);

	ХранилищеОбщихНастроек.Сохранить(КлючОбъекта, "", ТекущиеНастройки);
КонецПроцедуры	

// Проверяем настройки на корректность, сбрасываем в случае нарушения.
//    Возвращает структуру с ключом - именем настройки, значением содержит описанием ошибки или Неопределено
// при отсутствии ошибки для данного параметра
//
Функция ПроверитьКорректностьНастроек(КлючНастройки = "") Экспорт

	Результат = Новый Структура("ЕстьОшибки,
								|НастройкаАвторегистрацияДвижений, НастройкаАвторегистрацияПоследовательностей, 
								|НастройкаАдресВнешнейОбработкиЗапросов, НастройкаКонтрольВыгрузкиОбъектов,
								|НастройкаВариантНомераСообщения", Ложь);
		
	// Доступность внешней обработки
	Если ПустаяСтрока(НастройкаАдресВнешнейОбработкиЗапросов) Тогда
		// Убираем возможные пробелы, вариант отключен
		НастройкаАдресВнешнейОбработкиЗапросов = "";

	ИначеЕсли НРег(Прав(СокрЛП(НастройкаАдресВнешнейОбработкиЗапросов), 4)) = ".epf" Тогда
		// Файл обработки
		Файл = Новый Файл(НастройкаАдресВнешнейОбработкиЗапросов);
		Если Не Файл.Существует() Тогда
			Текст = НСтр("ru='Файл ""%1"" не доступен %2'");

			Текст = СтрЗаменить(Текст, "%1", НастройкаАдресВнешнейОбработкиЗапросов);
			Если ЭтоФайловаяБаза() Тогда
				РасположениеФайла = "";
			Иначе
				РасположениеФайла = НСтр("ru='на сервере'");
			КонецЕсли;

			Текст = СтрЗаменить(Текст, "%2", РасположениеФайла);
			Результат.НастройкаАдресВнешнейОбработкиЗапросов = Текст;

			Результат.ЕстьОшибки = Истина;
		КонецЕсли;

	Иначе
		// В составе конфигурации
		Если Метаданные.Обработки.Найти(НастройкаАдресВнешнейОбработкиЗапросов) = Неопределено Тогда
			Текст = НСтр("ru='Обработка ""%1"" не найдена в составе конфигурации'");
			Результат.НастройкаАдресВнешнейОбработкиЗапросов = СтрЗаменить(Текст, "%1",
				НастройкаАдресВнешнейОбработкиЗапросов);

			Результат.ЕстьОшибки = Истина;
		КонецЕсли;

	КонецЕсли;

	Возврат Результат;
КонецФункции

// Служебное для регистрации в подключаемых обработках
//
Функция СведенияОВнешнейОбработке() Экспорт

	Инфо = Новый Структура("Вид, Команды, БезопасныйРежим, Назначение, Наименование, Версия, Информация, ВерсияБСП",
		"СозданиеСвязанныхОбъектов", Новый ТаблицаЗначений, Истина, Новый Массив);

	Инфо.Наименование = НСтр("ru='Регистрация изменений для обмена данными'");
	Инфо.Версия       = "0.1";
	Инфо.ВерсияБСП    = "1.2.1.4";
	Инфо.Информация   = НСтр("ru='"
		+ "Обработка для управления регистрацией объектов на узлах обмена до формирования выгрузки. "
		+ "При работе в составе конфигурации с БСП версии 2.1.2.0 и старше производит контроль "
		+ "ограничений миграции данных для узлов обмена." + "'");

	Инфо.Назначение.Добавить("ПланыОбмена.*");
	Инфо.Назначение.Добавить("Константы.*");
	Инфо.Назначение.Добавить("Справочники.*");
	Инфо.Назначение.Добавить("Документы.*");
	Инфо.Назначение.Добавить("Последовательности.*");
	Инфо.Назначение.Добавить("ПланыВидовХарактеристик.*");
	Инфо.Назначение.Добавить("ПланыСчетов.*");
	Инфо.Назначение.Добавить("ПланыВидовРасчета.*");
	Инфо.Назначение.Добавить("РегистрыСведений.*");
	Инфо.Назначение.Добавить("РегистрыНакопления.*");
	Инфо.Назначение.Добавить("РегистрыБухгалтерии.*");
	Инфо.Назначение.Добавить("РегистрыРасчета.*");
	Инфо.Назначение.Добавить("БизнесПроцессы.*");
	Инфо.Назначение.Добавить("Задачи.*");

	Колонки = Инфо.Команды.Колонки;
	ТипСтрока = Новый ОписаниеТипов("Строка");
	Колонки.Добавить("Представление", ТипСтрока);
	Колонки.Добавить("Идентификатор", ТипСтрока);
	Колонки.Добавить("Использование", ТипСтрока);
	Колонки.Добавить("Модификатор", ТипСтрока);
	Колонки.Добавить("ПоказыватьОповещение", Новый ОписаниеТипов("Булево"));
	
	// Единственная команда, что делать - определяем по типу переданного
	Команда = Инфо.Команды.Добавить();
	Команда.Представление = НСтр("ru='Редактирование регистрации изменений объекта'");
	Команда.Идентификатор = "ОткрытьФормуРедактированияРегистрации";
	Команда.Использование = "ОткрытиеФормы";

	Возврат Инфо;
КонецФункции

////////////////////////////////////////////////////////////////////////////////////////////////////
// СЛУЖЕБНЫЕ ПРОЦЕДУРЫ И ФУНКЦИИ
//

//
// Копирует отбор компоновки данных
//
Процедура СкопироватьОтборКомпоновкиДанных(ГруппаПриемник, ГруппаИсточник)

	КоллекцияИсточник = ГруппаИсточник.Элементы;
	КоллекцияПриемник = ГруппаПриемник.Элементы;
	Для Каждого Элемент Из КоллекцияИсточник Цикл
		ТипЭлемента  = ТипЗнч(Элемент);
		НовыйЭлемент = КоллекцияПриемник.Добавить(ТипЭлемента);

		ЗаполнитьЗначенияСвойств(НовыйЭлемент, Элемент);
		Если ТипЭлемента = Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
			СкопироватьОтборКомпоновкиДанных(НовыйЭлемент, Элемент);
		КонецЕсли
		;

	КонецЦикла;

КонецПроцедуры

// Выполняет непосредственное действие с конечным объектом
//
Процедура ВыполнитьКомандуРегистрацииОбъекта(Знач Команда, Знач Узел, Знач ОбъектРегистрации)

	Если ТипЗнч(Команда) = Тип("Булево") Тогда
		Если Команда Тогда
			// Регистрация
			Если НастройкаВариантНомераСообщения = 1 Тогда
				// Как отправленного
				Команда = 1 + Узел.НомерОтправленного;
			Иначе
				// Как нового
				ЗарегистрироватьИзменения(Узел, ОбъектРегистрации);
			КонецЕсли;
		Иначе
			// Отмена регистрации
			ПланыОбмена.УдалитьРегистрациюИзменений(Узел, ОбъектРегистрации);
		КонецЕсли;
	КонецЕсли;

	Если ТипЗнч(Команда) = Тип("Число") Тогда
		// Одиночная регистрация с указанным номером сообщения
		Если Команда = 0 Тогда
			// Аналогично регистрации нового
			ЗарегистрироватьИзменения(Узел, ОбъектРегистрации);
		Иначе
			// Изменение номера регистрации, БСП не проверяем
			ПланыОбмена.ЗарегистрироватьИзменения(Узел, ОбъектРегистрации);
			Выборка = ПланыОбмена.ВыбратьИзменения(Узел, Команда, ОбъектРегистрации);
			Пока Выборка.Следующий() Цикл
				// Выбираем изменения для простановки номера сообщения обмена данными
			КонецЦикла;
		КонецЕсли;

	КонецЕсли;

КонецПроцедуры

Процедура ЗарегистрироватьИзменения(Знач Узел, Знач ОбъектРегистрации)

	Если Не ДоступнаРегистрацияСредствамиБСП Тогда
		ПланыОбмена.ЗарегистрироватьИзменения(Узел, ОбъектРегистрации);
	КонецЕсли;
		
	// Заводим на регистрацию в БСП всегда, необходимы дополнительные действия
	МодульБСП = Вычислить("ОбменДаннымиСобытия");
	
	// На входе или объект метаданных или непосредственно объект
	Если ТипЗнч(ОбъектРегистрации) = Тип("ОбъектМетаданных") Тогда
		Характеристики = ХарактеристикиПоМетаданным(ОбъектРегистрации);
		Если Характеристики.ЭтоСсылка Тогда
			Выборка = Характеристики.Менеджер.Выбрать();
			Пока Выборка.Следующий() Цикл
				МодульБСП.ЗарегистрироватьИзмененияДанных(Узел, Выборка.Ссылка,
					ЭтотОбъект.НастройкаКонтрольВыгрузкиОбъектов);
			КонецЦикла;
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	// Обычный объект
	МодульБСП.ЗарегистрироватьИзмененияДанных(Узел, ОбъектРегистрации, ЭтотОбъект.НастройкаКонтрольВыгрузкиОбъектов);
КонецПроцедуры

// Возвращает управляемую форму, которой принадлежит элемент
//
Функция ФормаЭлементаФормы(ЭлементФормы)
	Результат = ЭлементФормы;
	//@skip-warning
	ТипыФормы = Новый ОписаниеТипов("УправляемаяФорма");
	Пока Не ТипыФормы.СодержитТип(ТипЗнч(Результат)) Цикл
		Результат = Результат.Родитель;
	КонецЦикла;
	Возврат Результат;
КонецФункции

// Внутренняя для формирования группы метаданных (например справочников) в дереве метаданных
//
Процедура СформироватьУровеньМетаданных(ТекущийНомерСтроки, Параметры, ИндексКартинки, ИндексКартинкиУзлов,
	ДобавлятьПодчиненные, ИмяМета, ПредставлениеМета)

	ПредставленияУровня = Новый Массив;
	Авторегистрации     = Новый Массив;
	ИменаУровня         = Новый Массив;

	ВсеСтроки = Параметры.Строки;
	МетаПлан  = Параметры.ПланОбмена;

	СтрокаГруппа = ВсеСтроки.Добавить();
	СтрокаГруппа.ИдентификаторСтроки = ТекущийНомерСтроки;

	СтрокаГруппа.МетаПолноеИмя  = ИмяМета;
	СтрокаГруппа.Наименование   = ПредставлениеМета;
	СтрокаГруппа.ИндексКартинки = ИндексКартинки;

	Строки = СтрокаГруппа.Строки;
	БылиПодчиненные = Ложь;

	Для Каждого Мета Из Метаданные[ИмяМета] Цикл

		Если МетаПлан = Неопределено Тогда
			// Без учета плана обмена
			БылиПодчиненные = Истина;
			МетаПолноеИмя   = Мета.ПолноеИмя();
			Наименование    = Мета.Представление();
			Если ДобавлятьПодчиненные Тогда
				НовСтрока = Строки.Добавить();
				НовСтрока.МетаПолноеИмя  = МетаПолноеИмя;
				НовСтрока.Наименование   = Наименование;
				НовСтрока.ИндексКартинки = ИндексКартинкиУзлов;

				ТекущийНомерСтроки = ТекущийНомерСтроки + 1;
				НовСтрока.ИдентификаторСтроки = ТекущийНомерСтроки;
			КонецЕсли;
			ИменаУровня.Добавить(МетаПолноеИмя);
			ПредставленияУровня.Добавить(Наименование);

		Иначе
			Элемент = МетаПлан.Состав.Найти(Мета);
			Если Элемент <> Неопределено Тогда
				БылиПодчиненные = Истина;
				МетаПолноеИмя   = Мета.ПолноеИмя();
				Наименование    = Мета.Представление();
				Авторегистрация = ?(Элемент.Авторегистрация = АвтоРегистрацияИзменений.Запретить, 1, 2);
				Если ДобавлятьПодчиненные Тогда
					НовСтрока = Строки.Добавить();
					НовСтрока.МетаПолноеИмя   = МетаПолноеИмя;
					НовСтрока.Наименование    = Наименование;
					НовСтрока.ИндексКартинки  = ИндексКартинкиУзлов;
					НовСтрока.Авторегистрация = Авторегистрация;

					ТекущийНомерСтроки = ТекущийНомерСтроки + 1;
					НовСтрока.ИдентификаторСтроки = ТекущийНомерСтроки;
				КонецЕсли;
				ИменаУровня.Добавить(МетаПолноеИмя);
				ПредставленияУровня.Добавить(Наименование);
				Авторегистрации.Добавить(Авторегистрация);
			КонецЕсли;
		КонецЕсли;

	КонецЦикла;

	Если БылиПодчиненные Тогда
		Строки.Сортировать("Наименование");
		Параметры.СтруктураИмен.Вставить(ИмяМета, ИменаУровня);
		Параметры.СтруктураПредставлений.Вставить(ИмяМета, ПредставленияУровня);
		Если Не ДобавлятьПодчиненные Тогда
			Параметры.СтруктураАвторегистрации.Вставить(ИмяМета, Авторегистрации);
		КонецЕсли;
	Иначе
		// Виды объектов без регистрации не вставляем
		ВсеСтроки.Удалить(СтрокаГруппа);
	КонецЕсли;

КонецПроцедуры

// Накапливаем результаты регистраций
//
Процедура ДобавитьРезультаты(Приемник, Источник)
	Приемник.Успешно = Приемник.Успешно + Источник.Успешно;
	Приемник.Всего   = Приемник.Всего + Источник.Всего;
КонецПроцедуры	

// Возвращает массив дополнительно регистрируемых объектов согласно флагам
//
Функция ПолучитьДополнительныеОбъектыРегистрации(ОбъектРегистрации, УзелКонтроляАвторегистрации, БезАвторегистрации,
	ИмяТаблицы = Неопределено)
	Результат = Новый Массив;
	
	// Смотрим на глобальные параметры
	Если (Не НастройкаАвторегистрацияДвижений) И (Не НастройкаАвторегистрацияПоследовательностей) Тогда
		Возврат Результат;
	КонецЕсли;

	ТипЗначения = ТипЗнч(ОбъектРегистрации);
	НаВходеИмя = ТипЗначения = Тип("Строка");
	Если НаВходеИмя Тогда
		Описание = ХарактеристикиПоМетаданным(ОбъектРегистрации);
	ИначеЕсли ТипЗначения = Тип("Структура") Тогда
		Описание = ХарактеристикиПоМетаданным(ИмяТаблицы);
		Если Описание.ЭтоПоследовательность Тогда
			Возврат Результат;
		КонецЕсли;
	Иначе
		Описание = ХарактеристикиПоМетаданным(ОбъектРегистрации.Метаданные());
	КонецЕсли;

	МетаОбъект = Описание.Метаданные;
	
	// Коллекцию рекурсивно	
	Если Описание.ЭтоКоллекция Тогда
		Для Каждого Мета Из МетаОбъект Цикл
			ДополнительныйНабор = ПолучитьДополнительныеОбъектыРегистрации(Мета.ПолноеИмя(),
				УзелКонтроляАвторегистрации, БезАвторегистрации, ИмяТаблицы);
			Для Каждого Элемент Из ДополнительныйНабор Цикл
				Результат.Добавить(Элемент);
			КонецЦикла;
		КонецЦикла;
		Возврат Результат;
	КонецЕсли;
	
	// Одиночное
	СоставУзла = УзелКонтроляАвторегистрации.Метаданные().Состав;
	
	// Документы. Могут влиять на последовательности и движения
	Если Метаданные.Документы.Содержит(МетаОбъект) Тогда

		Если НастройкаАвторегистрацияДвижений Тогда
			Для Каждого Мета Из МетаОбъект.Движения Цикл

				ЭлементСостава = СоставУзла.Найти(Мета);
				Если ЭлементСостава <> Неопределено И (БезАвторегистрации Или ЭлементСостава.Авторегистрация
					= АвтоРегистрацияИзменений.Разрешить) Тогда
					Если НаВходеИмя Тогда
						Результат.Добавить(Мета);
					Иначе
						Описание = ХарактеристикиПоМетаданным(Мета);
						Набор = Описание.Менеджер.СоздатьНаборЗаписей();
						Набор.Отбор.Регистратор.Установить(ОбъектРегистрации);
						Набор.Прочитать();
						Результат.Добавить(Набор);
						// И проверим полученный набор рекурсивно
						ДополнительныйНабор = ПолучитьДополнительныеОбъектыРегистрации(Набор,
							УзелКонтроляАвторегистрации, БезАвторегистрации, ИмяТаблицы);
						Для Каждого Элемент Из ДополнительныйНабор Цикл
							Результат.Добавить(Элемент);
						КонецЦикла;
					КонецЕсли;
				КонецЕсли;

			КонецЦикла;
		КонецЕсли;

		Если НастройкаАвторегистрацияПоследовательностей Тогда
			Для Каждого Мета Из Метаданные.Последовательности Цикл

				Описание = ХарактеристикиПоМетаданным(Мета);
				Если Мета.Документы.Содержит(МетаОбъект) Тогда
					// Последовательность регистрируется для данного документа
					ЭлементСостава = СоставУзла.Найти(Мета);
					Если ЭлементСостава <> Неопределено И (БезАвторегистрации Или ЭлементСостава.Авторегистрация
						= АвтоРегистрацияИзменений.Разрешить) Тогда
						// Регистрируется на этом узле
						Если НаВходеИмя Тогда
							Результат.Добавить(Мета);
						Иначе
							Набор = Описание.Менеджер.СоздатьНаборЗаписей();
							Набор.Отбор.Регистратор.Установить(ОбъектРегистрации);
							Набор.Прочитать();
							Результат.Добавить(Набор);
						КонецЕсли;
					КонецЕсли;
				КонецЕсли;

			КонецЦикла;

		КонецЕсли;
		
	// Записи регистров. Могут влиять на последовательности
	ИначеЕсли НастройкаАвторегистрацияПоследовательностей И (Метаданные.РегистрыСведений.Содержит(МетаОбъект)
		Или Метаданные.РегистрыНакопления.Содержит(МетаОбъект) Или Метаданные.РегистрыБухгалтерии.Содержит(МетаОбъект)
		Или Метаданные.РегистрыРасчета.Содержит(МетаОбъект)) Тогда
		Для Каждого Мета Из Метаданные.Последовательности Цикл
			Если Мета.Движения.Содержит(МетаОбъект) Тогда
				// Последовательность регистрируется для набора записей
				ЭлементСостава = СоставУзла.Найти(Мета);
				Если ЭлементСостава <> Неопределено И (БезАвторегистрации Или ЭлементСостава.Авторегистрация
					= АвтоРегистрацияИзменений.Разрешить) Тогда
					Результат.Добавить(Мета);
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;

	КонецЕсли;

	Возврат Результат;
КонецФункции

// Преобразует строку в число
//
// Параметры:
//     Текст - Строка - строковое представление числа
// 
// Возвращаемое значение:
//     Число        - преобразованная строка
//     Неопределено - если строка не может быть преобразована
//
Функция СтрокаВЧисло(Знач Текст)
	ТекстЧисла = СокрЛП(СтрЗаменить(Текст, Символы.НПП, ""));

	Если ПустаяСтрока(ТекстЧисла) Тогда
		Возврат 0;
	КонецЕсли;
	
	// Ведущие нули
	Позиция = 1;
	Пока Сред(ТекстЧисла, Позиция, 1) = "0" Цикл
		Позиция = Позиция + 1;
	КонецЦикла;
	ТекстЧисла = Сред(ТекстЧисла, Позиция);
	
	// Проверяем на результат по умолчанию
	Если ТекстЧисла = "0" Тогда
		Результат = 0;
	Иначе
		ТипЧисло = Новый ОписаниеТипов("Число");
		Результат = ТипЧисло.ПривестиЗначение(ТекстЧисла);
		Если Результат = 0 Тогда
			// Результат по умолчанию обработан выше, это ошибка преобразования
			Результат = Неопределено;
		КонецЕсли;
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Возвращает флаг того, что БСП в текущей конфигурации обеспечивает функционал
//
Функция БСП_ДоступнаТребуемаяВерсия(Знач Версия = Неопределено) Экспорт

	НужнаяВерсия = СтрЗаменить(?(Версия = Неопределено, "2.1.2", Версия), ".", Символы.ПС);

	Попытка
		ТекущаяВерсия = Вычислить("СтандартныеПодсистемыСервер.ВерсияБиблиотеки()");
	Исключение
		// Отсутствует или поломан метод определения версии, считаем БСП недоступной
		Возврат Ложь;
	КонецПопытки;

	ТекущаяВерсия = СтрЗаменить(ТекущаяВерсия, ".", Символы.ПС);

	Для Индекс = 1 По СтрЧислоСтрок(НужнаяВерсия) Цикл

		ЧастьТекущейВерсии = СтрокаВЧисло(СтрПолучитьСтроку(ТекущаяВерсия, Индекс));
		ЧастьНужнойВерсии  = СтрокаВЧисло(СтрПолучитьСтроку(НужнаяВерсия, Индекс));

		Если ЧастьТекущейВерсии = Неопределено Тогда
			Возврат Ложь;
		ИначеЕсли ЧастьТекущейВерсии > ЧастьНужнойВерсии Тогда
			Возврат Истина;
		ИначеЕсли ЧастьТекущейВерсии < ЧастьНужнойВерсии Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;

	Возврат Истина;
КонецФункции

// Возвращает флаг контроля объекта в БСП
//
Функция БСП_КонтрольВыгрузкиОбъекта(Узлы, ОбъектРегистрации)
	Отправка = ОтправкаЭлементаДанных.Авто;
	Выполнить ("ОбменДаннымиСобытия.ПриОтправкеДанныхКорреспонденту(ОбъектРегистрации, Отправка, , Узлы)");
	Возврат Отправка <> ОтправкаЭлементаДанных.Удалить;
КонецФункции

// Проверяет ссылку на возможность регистрации изменения в БСП.
// Возвращает структуру с полями "Всего" и "Успешно", описывающей количества регистраций
//
Функция БСП_РегистрацияИзмененийСсылки(Узел, Ссылка, БезУчетаАвторегистрации = Истина)

	Результат = Новый Структура("Всего, Успешно", 0, 0);

	Если БезУчетаАвторегистрации Тогда
		СоставУзла = Неопределено;
	Иначе
		СоставУзла = Узел.Метаданные().Состав;
	КонецЕсли;

	ЭлементСостава = ?(СоставУзла = Неопределено, Неопределено, СоставУзла.Найти(Ссылка.Метаданные()));
	Если ЭлементСостава = Неопределено Или ЭлементСостава.Авторегистрация = АвтоРегистрацияИзменений.Разрешить Тогда
		// Сам объект
		Результат.Всего = 1;
		ОбъектРегистрации = Ссылка.ПолучитьОбъект();
		// Для битых ссылок ОбъектРегистрации будет Неопределено
		Если ОбъектРегистрации = Неопределено Или БСП_КонтрольВыгрузкиОбъекта(Узел, ОбъектРегистрации) Тогда
			ВыполнитьКомандуРегистрацииОбъекта(Истина, Узел, Ссылка);
			Результат.Успешно = 1;
		КонецЕсли;
		ОбъектРегистрации = Неопределено;
	КонецЕсли;	
	
	// Смотрим опциональные варианты
	Если Результат.Успешно > 0 Тогда
		Для Каждого Элемент Из ПолучитьДополнительныеОбъектыРегистрации(Ссылка, Узел, БезУчетаАвторегистрации) Цикл
			Результат.Всего = Результат.Всего + 1;
			Если БСП_КонтрольВыгрузкиОбъекта(Узел, Элемент) Тогда
				ВыполнитьКомандуРегистрацииОбъекта(Истина, Узел, Элемент);
				Результат.Успешно = Результат.Успешно + 1;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Проверяет набор значений на возможность регистрации изменения в БСП.
// Возвращает структуру с полями "Всего" и "Успешно", описывающей количества регистраций
//
Функция БСП_РегистрацияИзмененийНабора(Узел, СтруктураПолей, Описание, БезУчетаАвторегистрации = Истина)

	Результат = Новый Структура("Всего, Успешно", 0, 0);

	Если БезУчетаАвторегистрации Тогда
		СоставУзла = Неопределено;
	Иначе
		СоставУзла = Узел.Метаданные().Состав;
	КонецЕсли;

	ЭлементСостава = ?(СоставУзла = Неопределено, Неопределено, СоставУзла.Найти(Описание.Метаданные));
	Если ЭлементСостава = Неопределено Или ЭлементСостава.Авторегистрация = АвтоРегистрацияИзменений.Разрешить Тогда
		Результат.Всего = 1;

		Набор = Описание.Менеджер.СоздатьНаборЗаписей();
		Для Каждого КлючЗначение Из СтруктураПолей Цикл
			Набор.Отбор[КлючЗначение.Ключ].Установить(КлючЗначение.Значение);
		КонецЦикла;
		Набор.Прочитать();

		Если БСП_КонтрольВыгрузкиОбъекта(Узел, Набор) Тогда
			ВыполнитьКомандуРегистрацииОбъекта(Истина, Узел, Набор);
			Результат.Успешно = 1;
		КонецЕсли;

	КонецЕсли;
	
	// Смотрим опциональные варианты
	Если Результат.Успешно > 0 Тогда
		Для Каждого Элемент Из ПолучитьДополнительныеОбъектыРегистрации(Набор, Узел, БезУчетаАвторегистрации) Цикл
			Результат.Всего = Результат.Всего + 1;
			Если БСП_КонтрольВыгрузкиОбъекта(Узел, Элемент) Тогда
				ВыполнитьКомандуРегистрацииОбъекта(Истина, Узел, Элемент);
				Результат.Успешно = Результат.Успешно + 1;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Проверяет константу на возможность регистрации изменения в БСП.
// Возвращает структуру с полями "Всего" и "Успешно", описывающей количества регистраций
//
Функция БСП_РегистрацияИзмененийКонстанты(Узел, Описание, БезУчетаАвторегистрации = Истина)

	Результат = Новый Структура("Всего, Успешно", 0, 0);

	Если БезУчетаАвторегистрации Тогда
		СоставУзла = Неопределено;
	Иначе
		СоставУзла = Узел.Метаданные().Состав;
	КонецЕсли;

	ЭлементСостава = ?(СоставУзла = Неопределено, Неопределено, СоставУзла.Найти(Описание.Метаданные));
	Если ЭлементСостава = Неопределено Или ЭлементСостава.Авторегистрация = АвтоРегистрацияИзменений.Разрешить Тогда
		Результат.Всего = 1;
		ОбъектРегистрации = Описание.Менеджер.СоздатьМенеджерЗначения();
		Если БСП_КонтрольВыгрузкиОбъекта(Узел, ОбъектРегистрации) Тогда
			ВыполнитьКомандуРегистрацииОбъекта(Истина, Узел, ОбъектРегистрации);
			Результат.Успешно = 1;
		КонецЕсли;

	КонецЕсли;

	Возврат Результат;
КонецФункции

// Проверяет набор метаданных на возможность регистрации изменения в БСП.
// Возвращает структуру с полями "Всего" и "Успешно", описывающей количества регистраций
//
Функция БСП_РегистрацияИзмененийМетаданных(Узел, Описание, БезУчетаАвторегистрации)

	Результат = Новый Структура("Всего, Успешно", 0, 0);

	Если Описание.ЭтоКоллекция Тогда
		Для Каждого МетаВид Из Описание.Метаданные Цикл
			ТекОписание = ХарактеристикиПоМетаданным(МетаВид);
			ДобавитьРезультаты(Результат, БСП_РегистрацияИзмененийМетаданных(Узел, ТекОписание,
				БезУчетаАвторегистрации));
		КонецЦикла;
	Иначе
		;
		ДобавитьРезультаты(Результат, БСП_РегистрацияИзмененийОбъектаМетаданных(Узел, Описание,
			БезУчетаАвторегистрации));
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Проверяет объект метаданных на возможность регистрации изменения в БСП.
// Возвращает структуру с полями "Всего" и "Успешно", описывающей количества регистраций
//
Функция БСП_РегистрацияИзмененийОбъектаМетаданных(Узел, Описание, БезУчетаАвторегистрации)

	Результат = Новый Структура("Всего, Успешно", 0, 0);

	ЭлементСостава = Узел.Метаданные().Состав.Найти(Описание.Метаданные);
	Если ЭлементСостава = Неопределено Тогда
		// Вообще не регистрируется
		Возврат Результат;
	КонецЕсли;

	Если (Не БезУчетаАвторегистрации) И ЭлементСостава.Авторегистрация <> АвтоРегистрацияИзменений.Разрешить Тогда
		// Отсечение по авторегистрации
		Возврат Результат;
	КонецЕсли;

	ТекИмяТаблицы = Описание.ИмяТаблицы;
	Если Описание.ЭтоКонстанта Тогда
		ДобавитьРезультаты(Результат, БСП_РегистрацияИзмененийКонстанты(Узел, Описание));
		Возврат Результат;

	ИначеЕсли Описание.ЭтоСсылка Тогда
		ПоляИзмерений = "Ссылка";

	ИначеЕсли Описание.ЭтоНабор Тогда
		ПоляИзмерений = "";
		Для Каждого Строка Из ИзмеренияНабораЗаписей(ТекИмяТаблицы) Цикл
			ПоляИзмерений = ПоляИзмерений + "," + Строка.Имя;
		КонецЦикла
		;
		ПоляИзмерений = Сред(ПоляИзмерений, 2);

	Иначе
		Возврат Результат;
	КонецЕсли;

	Запрос = Новый Запрос("
						  |ВЫБРАТЬ РАЗЛИЧНЫЕ 
						  |	" + ?(ПустаяСтрока(ПоляИзмерений), "*", ПоляИзмерений) + "
																						|ИЗ 
																						|	" + ТекИмяТаблицы + "
																												 |");
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Если Описание.ЭтоНабор Тогда
			Данные = Новый Структура(ПоляИзмерений);
			ЗаполнитьЗначенияСвойств(Данные, Выборка);
			ДобавитьРезультаты(Результат, БСП_РегистрацияИзмененийНабора(Узел, Данные, Описание));
		ИначеЕсли Описание.ЭтоСсылка Тогда
			ДобавитьРезультаты(Результат, БСП_РегистрацияИзмененийСсылки(Узел, Выборка.Ссылка, БезУчетаАвторегистрации));
		КонецЕсли;
	КонецЦикла;

	Возврат Результат;
КонецФункции

#КонецЕсли